#include "vgdb.h"


/*
 *  默认正常情况下每行都有\n 或者\0
 *  但是行中间不会有\0 若出现\0 必然是行末尾
 *  state = fdgetline( fd, buff, blen, &len )
 *  buff  :为一行数据, 如果正常读取(state>0),以'\0'填充结尾, 否则没有'\0'
 *  len   :若正常读取, 则装欢行末的\n为\0后的数据串长度 否则为异常发生之前的成功读取的长度
 *  state :为读取数据状态
 *         -5 : buff为空
 *         -4 : len为空
 *         -3 : blen<=0
 *         -2 : 缓冲区读满
 *         -1 : read调用错
 *          0 : fd已经关闭/无数据可读/到达末尾
 *          1 : 正常读取
 */

static int fdgetline(int fd, char *buff, int blen, int *len)
{
    int     ret_len;

    if(!buff){
        return -5;
    }
    if(!len){
        return -4;
    }
    if(blen <= 0){
        return -3;
    }

    ret_len = 0;
    while(ret_len<blen){
        switch(read(fd, buff+ret_len, 1)){
            case 1:
                if((*(buff+ret_len) == '\n') || (*(buff+ret_len) == '\0')){
                    *(buff+ret_len) = '\0';
                    *len = ret_len;
                    return 1;
                }else{
                    ret_len++;
                }
                break;
            case 0:
                *len = ret_len;
                return 0;
            default:
                *len = ret_len;
                return -1;
        }
    }
    *len = ret_len;
    return -2;
}


/*
 *  state = fdgetlines( fd, buff, blen, bnr, &cols, end )
 *  buff  :每行数据, 如果正常读取(state>0),以'\0'填充结尾, 否则没有'\0'
 *  cols  :读取的行数 包含不成功的半行 包含成功后的end行
 *  len   :最后一行的长度 考虑到异常的问题
 *  state :为读取数据状态
 *        -10 : unkown error
 *         -9 : buff为空
 *         -8 : cols为空
 *         -7 : len为空
 *         -6 : end为空
 *         -5 : blen<=0
 *         -4 : bnr<=0
 *         -3 : 行读满
 *         -2 : 行内读满
 *         -1 : read调用错
 *          0 : sock已经关闭/无数据可读/到达末尾
 *          1 : 成功读取行数 不包含不成功的行
 */

int fdgetlines(int fd, char *buff, int blen, int bnr, int *cols, int *len, const char *end)
{
    int     ind, ret, len_line;
    if(!buff){
        return -9;
    }
    if(!cols){
        return -8;
    }
    if(!len){
        return -7;
    }
    if(!end){
        return -6;
    }
    if(blen <= 0){
        return -5;
    }
    if(bnr <= 0){
        return -4;
    }

    ind = 0;
    while(ind < bnr){
        ret = fdgetline(fd, buff+ind*blen, blen, &len_line);
        switch(ret){
            case -5:
            case -4:
            case -3:
                *len  = len_line;
                *cols = ind;
                return -10;
            case -2:
            case -1:
            case  0:
                *len  = len_line;
                *cols = ind;
                return ret;
            default:
                //1
                if(!strcmp(buff+ind*blen, end)){
                    *len  = len_line;
                    *cols = ind+1;
                    return 1;
                }else{
                    ind++;
                }
        }
    }
    *len  = len_line;
    *cols = ind;
    return -3;
}

/*
 *  state = gdb_outp() 获取有效输出
 *  state : 为读取数据状态
 *         -1 : 读取output出错
 *        >=0 : 成功读取行数
 *  gdb()->cur : 输出当前行 此行可能为正常也可能为不正常
 *  gdb()->outp: 消息类型:ERROR/MESSAGE
 */

int gdb_outp()
{
    int     ret, cols, len;
    ret = fdgetlines(gdb()->rwfd, gdb_opln(1), gdb()->blen, gdb()->bnr-1, &cols, &len, "\x1a\x1aprompt");
    if(ret > 0){
        gdb()->bcur = cols - 4;

        int i;
        for(i=0;i<=gdb()->bcur;i++){
            DEBUG_MESSAGE("line = %2d| %s\n",i, gdb_opln(i));
        }
        return 1;
    }else{
        gdb()->bcur = cols;
        return -1;
    }
}

int gdb_opto(const char* end)
{
    int     ret, cols, len;
    ret = fdgetlines(gdb()->rwfd, gdb_opln(1), gdb()->blen, gdb()->bnr-1, &cols, &len, end);
    if(ret > 0){
        return 1;
    }else{
        return -1;
    }
}


void gdb_start()
{
    struct termios  stermios;

    if(tcgetattr(STDIN_FILENO,&stermios) >= 0) {
        stermios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
        stermios.c_oflag &= ~(ONLCR);
        tcsetattr(STDIN_FILENO,TCSANOW,&stermios);
    }
    execlp("gdb","gdb","-q", "--annotate=3",(char *) NULL);
}


void gdb_init()
{

    gdb()->pid   = -1;
    gdb()->state = VGDB_GS_STOP;
    gdb()->rwfd  = -1;
    gdb()->blen  = VGDB_OUTP_BLEN;
    gdb()->bnr   = VGDB_OUTP_BNR;
    gdb()->bcur  = 0;
}
